#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <functional>
#include <pthread.h>
#include "log.hpp"
#include "InetAddr.hpp"
#include "socket.hpp"

class tcpserver;

using http_t = std::function<std::string(std::string request)>;

class ThreadData
{
public:
    ThreadData(net::socket_ptr sockfd, InetAddr addr, tcpserver *s)
        : _sockfd(sockfd), _addr(addr), _s(s)
    {
    }
    net::socket_ptr _sockfd;
    InetAddr _addr;
    tcpserver *_s;
};

class tcpserver
{
public:
    tcpserver(uint16_t port, http_t service)
        : _listenSockPtr(std::make_unique<net::TcpSocket>()), _localaddr("0", port), isrunning(false), _http_service(service)
    {
        _listenSockPtr->BuildServerSocket(_localaddr);
    }

    static void *threadsocktask(void *argc)
    {
        ThreadData *p = (ThreadData *)argc;
        std::string request;
        ssize_t n = p->_sockfd->Recv(&request); // 读取请求
        if (n > 0)
        {
            std::string response = p->_s->_http_service(request);
            p->_sockfd->Send(response); // 发送应答
        }
        p->_sockfd->Close();
        delete p;
        return nullptr;
    }

    void start()
    {
        isrunning = true;
        while (isrunning)
        {
            InetAddr addr;
            net::socket_ptr sockptr = _listenSockPtr->Accept(&addr);
            if (sockptr == nullptr)
            {
                continue;
            }

            // 版本三:多线程
            pthread_t id;
            ThreadData *data = new ThreadData(sockptr, addr, this);
            pthread_create(&id, nullptr, &threadsocktask, data);
            pthread_detach(id);
        }
        isrunning = false;
    }

private:
    std::unique_ptr<net::Socket> _listenSockPtr;
    InetAddr _localaddr;
    bool isrunning;

    http_t _http_service;
};